unit oArrivalsManager;

{
	created   7.3.2010
	author    Michal Varga
	purpose   joins pedestrian types with arrivals
                  adds specific attributes needed for Enviroment Agent

	edit list:

        comment list:
}

interface

uses
  oManager, oProcessObjects, oPedestriansManager, Classes, oPathsManager, uOSPRand,
  oGeneratorData, SysUtils, oProcessItem, Generics.Collections, XMLDoc, XMLIntf, oFrameArrivalData,
  oStats;

type
  EArrivalsManager = class(Exception)
  end;

  ENotValidArrivalType = class(EArrivalsManager)
  end;

  EArrivalnNotExists = class(EArrivalsManager)
  end;

  EArrivalAlreadyExists = class(EArrivalsManager)
  end;

  TArrivalsManager = class(TManager)
    public
      type
        TArrivalType = class(TProcessable)
          strict private
            aPedestrian: TPedestrianManager.TPedestrianType;
            aPath: TPathsManager.TPathType;
            aCountGeneratorData: TGeneratorData;
            aNextArrivalGeneratorData: TGeneratorData;
            aCountGenerator: tRndm;
            aNextArrivalGenerator: tRndm;
            aArrivesFrom: Double;
            aArrivesTo: Double;
            aPedType: Integer;
            aName: String;
            aMaster: TManager;
            aActive: Boolean;
            aPeopleStat: TAddStat;
          private
            function getPeopleToArrive: Integer;
            function getNextArrival: Double;
            procedure setNextGenerator(const Value: tRndm);
            procedure setCountGenerator(const Value: tRndm);
          public
            property Active: Boolean read aActive write aActive;
            property Name: String read aName;
            property Pedestrian: TPedestrianManager.TPedestrianType read aPedestrian;
            property Path: TPathsManager.TPathType read aPath;
            property PeopleToArrive: Integer read getPeopleToArrive;
            property CountGenerator: tRndm read aCountGenerator write setCountGenerator;
            property ArrivesFrom: Double read aArrivesFrom;
            property ArrivesTo: Double read aArrivesTo;
            property NextArrival: Double read getNextArrival;
            property PedType: Integer read aPedType write aPedType;
            property NextArrivalGeneratorData: TGeneratorData read aNextArrivalGeneratorData write aNextArrivalGeneratorData;
            property NextGenerator: tRndm read aNextArrivalGenerator write setNextGenerator;
            property CountGeneratorData: TGeneratorData read aCountGeneratorData write aCountGeneratorData;
            property StatPeople: TAddStat read aPeopleStat write aPeopleStat;
            constructor create(paMaster: TManager;
                               paPedestrian: TPedestrianManager.TPedestrianType = nil;
                               paPath: TPathsManager.TPathType = nil;
                               paCountGeneratorData: TGeneratorData = nil;
                               paNextGeneratorData: TGeneratorData = nil;
                               paArrivesFrom: Double = 0; paArrivesTo: Double = 0;
                               paName: String = '';
                               paPedType: Integer = 0); overload;
            constructor create(paMaster: TManager;paData: TArrivalData); overload;
            destructor Destroy; override;
            procedure Assign(rhs: TArrivalData);
            procedure Save(var paWhere: IXMLNode);
            procedure Load(paFrom: IXMLNode);
        end;
    private
      aArrivals: TList<TArrivalType>;
      function search(paName: String): TArrivalType;
      procedure resetList;
      function exists(paName: String): boolean;
    public
      property Arrivals: TList<TArrivalType> read aArrivals;
      constructor create(paMaster: TManager);
      destructor Destroy; override;
      function ProcessObject(paItem: TProcessItem):TProcessItem; override; final;
  end;

implementation

uses
  oProcessObjectConstants, oRunPropertiesManager, oSimulation, Dialogs;

resourcestring eArrManNotValidType = 'not a valid processing type';
resourcestring eArrManNotValidConstant = 'not a valid constant';
resourcestring eArrManFoundDuplicity = 'entity already exists';
resourcestring eArrManPedestrianNotFound = 'predestrian not found';
resourcestring eArrManPathNotFound = 'path not found';
resourcestring eArrManArrivalNotFound = 'entity not found';

{ TArrivalsManager }



constructor TArrivalsManager.create(paMaster: TManager);
begin
  inherited create(paMaster);
  aArrivals := TList<TArrivalType>.create;
end;

destructor TArrivalsManager.destroy;
var
  arrival: TArrivalType;
begin
  for arrival in Arrivals do
    arrival.Free;
  Arrivals.Free;
  inherited;
end;

function TArrivalsManager.exists(paName: String): boolean;
var
  arrival: TArrivalType;
begin
  result := false;
  for arrival in Arrivals do
    if arrival.Name = paName then
    begin
      result := true;
      break;
    end;
end;

function TArrivalsManager.ProcessObject(paItem: TProcessItem): TProcessItem;
var
  arrival: TArrivalType;
  node: IXMLNode;
  i: Integer;
  strings : TStringList;
  tempI: TProcessItem;
  runprop: TRunPropertiesManager.TRunPropertiesType;
begin
  result := nil;
  try
    case paItem.Code of

      PO_ARRMAN_INSERT:
      begin
        if not(paItem.Data is TArrivalData) then raise Exception.Create('');
        arrival := TArrivalType.Create(aMaster,paItem.Data as TArrivalData);
        paItem.Free;
        paItem := Master.ProcessObject(TProcessItem.create(PO_PROJECT_INSERT_ARRIVAL,TString.Create(arrival.Name)));
        if (paItem.Data <> nil) and (paItem.Data is TProcessingXML) then
          begin
            node := ((paItem.Data) as TProcessingXML).Node;
            arrival.Save(node);
            Master.ProcessObject(TProcessItem.create(PO_PROJECT_CLOSE_XML, TProcessingXML.Create(node)));
            arrival.Free;
          end;
        paItem.Free;
      end;

      PO_ARRMAN_EDIT:
      begin
        if not(paItem.Data is TArrivalData) then raise ENotValidArrivalType.Create(eArrManNotValidType);
        arrival := search((paItem.Data as TArrivalData).Name);
        if arrival = nil then raise EArrivalnNotExists.Create('');
        arrival.Assign(paItem.Data as TArrivalData);
        paItem.Free;
        paItem := Master.ProcessObject(TProcessItem.create(PO_PROJECT_GET_ARRIVAL_XML,TString.Create(arrival.Name)));
        if (paItem.Data <> nil) and (paItem.Data is TProcessingXML) then
          begin
            node := ((paItem.Data) as TProcessingXML).Node;
            arrival.Save(node);
            Master.ProcessObject(TProcessItem.create(PO_PROJECT_CLOSE_XML, TProcessingXML.Create(node)));
//            arrival.Free;       lol   d(^_^)b
          end;
        paItem.Free;
      end;

      PO_ARRMAN_UNLOAD:
      begin
        for arrival in aArrivals do arrival.Free;
        aArrivals.Clear;
        paItem.Free;
      end;

      PO_ARRMAN_UNLOAD_ARRIVAL:
      begin
        if not(paItem.Data is TString) then raise Exception.Create('');
        arrival := search((paItem.Data as TString).String_);
        if arrival <> nil then aArrivals.Remove(arrival);
        paItem.Free;
      end;

      PO_ARRMAN_LOAD:
      begin
        if not(paItem.Data is TProcessingXML) then raise Exception.Create('');
        node := (paItem.Data as TProcessingXML).Node.ChildNodes.First;
        arrival := TArrivalType.Create(aMaster);
        arrival.Load(node);
        aArrivals.Add(arrival);
        paItem.Free;
        Result := nil;
       end;

      PO_ARRMAN_SAVE:
      begin
        if not(paItem.Data is TString) then raise Exception.Create('');
        tempI := Master.ProcessObject(TProcessItem.create(PO_PROJECT_INSERT_ARRIVAL,paItem.Data as TString));
        if paItem.Data <> nil then
          begin
            node := ((paItem.Data) as TProcessingXML).Node;
            arrival := search((paItem.Data as TString).String_);
            if arrival <> nil then arrival.Save(node);
            //Master.ProcessObject(TProcessItem.create(PO_PROJECT_CLOSE_XML, TProcessingXML.Create(node)));
          end;
        paItem.Free;
        tempI.Free;
      end;

      PO_ARRMAN_ACTIVATE:
      begin
        //inicializovanie statistik
        //kto pred zacatim simulacie nieco potrebuje od prichodov, nech to prida do tejto spravy!!!
        {tempI := Master.ProcessObject(TProcessItem.create(PO_RUNPROPMAN_GET_RUN_PROPERTIES,TString.Create((paItem.Data as TConfignData).RunConfig)));
        if (tempI.Data as TRunPropertiesManager.TRunPropertiesType).Stats.Items[ArrivalCount]
          then for arrival in aArrivals do
            begin
              arrival.StatPeople.Free;
              arrival.StatPeople := TAddStat.create;
            end
          else for arrival in aArrivals do
            begin
              arrival.StatPeople := TAddStat.create;
              arrival.StatPeople := nil;
            end;}
           for arrival in aArrivals do
            begin
              arrival.StatPeople.Free;
              arrival.StatPeople := TAddStat.create;
            end;
        result := nil;
      end;

      PO_ARRMAN_EXISTS:
      begin
        if not(paItem.Data is TString) then raise Exception.Create('');
        arrival := search((paItem.Data as TString).String_);
        if arrival <> nil
          then Result := TProcessItem.create(PO_SUCCESS,arrival)
          else Result := TProcessItem.create(PO_FAILURE,nil);
        //paItem.Free;
      end;

    end;

  except
    result := TProcessItem.create(PO_FAILURE,nil);
  end;

end;

procedure TArrivalsManager.resetList;
var
  arrival: TArrivalType;
begin
  for arrival in Arrivals do
    arrival.Free;
  Arrivals.Free;
  aArrivals := TList<TArrivalType>.create;
end;

function TArrivalsManager.search(paName: String): TArrivalType;
var
  arrival: TArrivalType;
begin
  for arrival in Arrivals do
    if arrival.Name = paName then
    begin
      result := arrival;
      exit;
    end;
  result := nil;
end;

{ TArrivalsManager.TArrivalType }

constructor TArrivalsManager.TArrivalType.create(
  paMaster: TManager;
  paPedestrian: TPedestrianManager.TPedestrianType;
  paPath: TPathsManager.TPathType;
  paCountGeneratorData: TGeneratorData;
  paNextGeneratorData: TGeneratorData;
  paArrivesFrom, paArrivesTo: Double;
  paName: String;
  paPedType: Integer);
var
  item: TProcessItem;
begin
  inherited create;
  aMaster := paMaster;
  aPedestrian := paPedestrian;
  aPath := paPath;
  aCountGeneratorData := paCountGeneratorData;
  aNextArrivalGeneratorData := paNextGeneratorData;
  item := aMaster.ProcessObject(TProcessItem.create(CONVERT_DATA_TO_GENERATOR,TProcessingGeneratorData.create(aCountGeneratorData)));
  aCountGenerator := (item.Data as TprocessingGenerator).Generator;
  item := aMaster.ProcessObject(TProcessItem.create(CONVERT_DATA_TO_GENERATOR,TProcessingGeneratorData.create(aNextArrivalGeneratorData)));
  aNextArrivalGenerator := (item.Data as TprocessingGenerator).Generator;
  aArrivesFrom := paArrivesFrom;
  aArrivesTo := paArrivesTo;
  aName := paName;
  aPedType := paPedType;
  item.Free;
end;

constructor TArrivalsManager.TArrivalType.create(paMaster: TManager;paData: TArrivalData);
begin
  inherited create;
  aPeopleStat := nil;
  aMaster := paMaster;
  Assign(paData);
end;

destructor TArrivalsManager.TArrivalType.Destroy;
begin
  //pedestrian and path can not be destroyed!!!
  aPedestrian := nil;
  aPath := nil;
  aMaster := nil;
  aCountGenerator.Free;
  aCountGeneratorData.Free;
  aNextArrivalGenerator.Free;
  aPeopleStat.Free;
  aNextArrivalGeneratorData.Free;
  inherited;
end;

function TArrivalsManager.TArrivalType.getNextArrival: Double;
begin
  result := aNextArrivalGeneratorData.Multiplier * aNextArrivalGenerator.Rand + aNextArrivalGeneratorData.Constant;
end;

function TArrivalsManager.TArrivalType.getPeopleToArrive: Integer;
var
  r: Integer;
begin
  r := Round(aCountGeneratorData.Multiplier * aCountGenerator.Rand + aCountGeneratorData.Constant);
  //r := 5;
  result := r;
end;

procedure TArrivalsManager.TArrivalType.Assign(rhs: TArrivalData);
var
  tempped: TPedestrianManager.TPedestrianType;
  temppath: TPathsManager.TPathType;

  item: TProcessItem;
begin
  tempped := nil;
  temppath := nil;
  //vyziadanie chodca
  item := aMaster.ProcessObject(TProcessItem.create(PO_PEDMAN_EXISTS,TString.Create(rhs.PedestrianID)));
  if item <> nil then tempped := item.Data as TPedestrianManager.TPedestrianType;
  item.Free;
  //vyziadanie cesty
  item := aMaster.ProcessObject(TProcessItem.create(PO_PATHS_GET_PATH,TString.Create(rhs.PathID)));
  if item <> nil then temppath := TPathsManager.TPathType((item.Data as TProcessingPath).Path);
  item.Free;
  //vyvolanie vynimky, ak som nedostal chodca alebo cestu
  if tempped = nil then raise EArrivalsManager.Create(eArrManPedestrianNotFound);
  if temppath = nil then raise EArrivalsManager.Create(eArrManPathNotFound);
  //samotne priradenie
  with rhs do
  begin
    aName := Name;
    aCountGeneratorData := CountGeneratorData;
    aNextArrivalGeneratorData := NextGeneratorData;
    aArrivesFrom := ArrivesFrom;
    aArrivesTo := ArrivesTo;
    aPedType := PedType;
  end;
  aPedestrian := tempped;
  aPath := temppath;
  //vytvorenie generatorov
  item := aMaster.ProcessObject(TProcessItem.create(CONVERT_DATA_TO_GENERATOR,TProcessingGeneratorData.create(rhs.CountGeneratorData)));
  aCountGenerator.Free;
  aCountGenerator := (item.Data as TprocessingGenerator).Generator;
  item := aMaster.ProcessObject(TProcessItem.create(CONVERT_DATA_TO_GENERATOR,TProcessingGeneratorData.create(rhs.NextGeneratorData)));
  aNextArrivalGenerator.Free;
  aNextArrivalGenerator := (item.Data as TprocessingGenerator).Generator;
  item.Free;
end;

procedure TArrivalsManager.TArrivalType.Load(paFrom: IXMLNode);
var
  tempped: TPedestrianManager.TPedestrianType;
  temppath: TPathsManager.TPathType;
  ArrTypeNode,ArrTypeAttribute: IXMLNode;
  str: String;
  item: TProcessItem;
  genProcData: TProcessingGeneratorData;
begin
  //name
  ArrTypeNode := paFrom;
  if ArrTypeNode.HasAttribute('name') then aName := ArrTypeNode.Attributes['name'];
  //pedestrian
  ArrTypeAttribute := ArrTypeNode.ChildNodes.FindNode('pedestrian');
  if ArrTypeAttribute.HasAttribute('value') then str := ArrTypeAttribute.Attributes['value'];
  item := aMaster.ProcessObject(TProcessItem.create(PO_PEDMAN_GET_PEDSTRIAN,TString.Create(str)));
  if item <> nil
    then tempped := (item.Data as TProcessingPedestrian).Pedestrian as TPedestrianManager.TPedestrianType
    else raise EArrivalsManager.Create(eArrManPedestrianNotFound);
  item.Free;
  aPedestrian := tempped;
  //path
  ArrTypeAttribute := ArrTypeNode.ChildNodes.FindNode('path');
  if ArrTypeAttribute.HasAttribute('value') then str := ArrTypeAttribute.Attributes['value'];
  item := aMaster.ProcessObject(TProcessItem.create(PO_PATHS_GET_PATH,TString.Create(str)));
  if item <> nil
    then temppath := (item.Data as TProcessingPath).Path as TPathsManager.TPathType
    else raise EArrivalsManager.Create(eArrManPathNotFound);
  item.Free;
  aPath := temppath;
  //arrivesFrom
  ArrTypeAttribute := ArrTypeNode.ChildNodes.FindNode('arrivesFrom');
  if ArrTypeAttribute.HasAttribute('value') then aArrivesFrom := ArrTypeAttribute.Attributes['value'];
  //arrivesTo
  ArrTypeAttribute := ArrTypeNode.ChildNodes.FindNode('arrivesTo');
  if ArrTypeAttribute.HasAttribute('value') then aArrivesTo := ArrTypeAttribute.Attributes['value'];
  //arrivesTo
  ArrTypeAttribute := ArrTypeNode.ChildNodes.FindNode('PedType');
  if (ArrTypeAttribute <> nil) and (ArrTypeAttribute.HasAttribute('value')) then PedType := ArrTypeAttribute.Attributes['value'];
  //count generator
  ArrTypeAttribute := ArrTypeNode.ChildNodes.FindNode('countGenerator');
  item := aMaster.ProcessObject(TProcessItem.create(LOAD_GENERATOR,TProcessingXML.Create(ArrTypeAttribute)));
  if item <> nil then
    begin
      genProcData := item.Data as TProcessingGeneratorData;
      aCountGeneratorData := genProcData.Data;
      item := aMaster.ProcessObject(TProcessItem.create(CONVERT_DATA_TO_GENERATOR,TProcessingGeneratorData.create(genProcData.Data)));
      aCountGenerator := (item.Data as TprocessingGenerator).Generator;
    end
    else raise EArrivalsManager.Create('');
  //next generator
  ArrTypeAttribute := ArrTypeNode.ChildNodes.FindNode('nextGenerator');
  item := aMaster.ProcessObject(TProcessItem.create(LOAD_GENERATOR,TProcessingXML.Create(ArrTypeAttribute)));
  if item <> nil then
    begin
      genProcData := item.Data as TProcessingGeneratorData;
      aNextArrivalGeneratorData := genProcData.Data;
      item := aMaster.ProcessObject(TProcessItem.create(CONVERT_DATA_TO_GENERATOR,TProcessingGeneratorData.create(genProcData.Data)));
      aNextArrivalGenerator := (item.Data as TprocessingGenerator).Generator;
    end
    else raise EArrivalsManager.Create('');
  item.Free;
end;

procedure TArrivalsManager.TArrivalType.Save(var paWhere: IXMLNode);
var ArrTypeNode,ArrTypeAttribute: IXMLNode;
begin
  try
    ArrTypeNode := paWhere.AddChild('ArrivalType');
    ArrTypeNode.Attributes['name'] := Name;
    ArrTypeAttribute := ArrTypeNode.AddChild('pedestrian');
    ArrTypeAttribute.Attributes['value'] := Pedestrian.Name;
    ArrTypeAttribute := ArrTypeNode.AddChild('path');
    ArrTypeAttribute.Attributes['value'] := Path.Name;
    ArrTypeAttribute := ArrTypeNode.AddChild('arrivesFrom');
    ArrTypeAttribute.Attributes['value'] := aArrivesFrom;
    ArrTypeAttribute := ArrTypeNode.AddChild('arrivesTo');
    ArrTypeAttribute.Attributes['value'] := aArrivesTo;
    ArrTypeAttribute := ArrTypeNode.AddChild('PedType');
    ArrTypeAttribute.Attributes['value'] := aPedType;
    ArrTypeAttribute := ArrTypeNode.AddChild('countGenerator');
    aMaster.ProcessObject(TProcessItem.create(SAVE_GENERATOR,TXMLGenerator.Create(ArrTypeAttribute,aCountGeneratorData)));
    ArrTypeAttribute := ArrTypeNode.AddChild('nextGenerator');
    aMaster.ProcessObject(TProcessItem.create(SAVE_GENERATOR,TXMLGenerator.Create(ArrTypeAttribute,aNextArrivalGeneratorData)));
  except
    on E:Exception do raise EArrivalsManager.Create('');
  end;
end;

procedure TArrivalsManager.TArrivalType.setCountGenerator(const Value: tRndm);
begin
  aCountGenerator.Free;
  aCountGenerator := Value;
end;

procedure TArrivalsManager.TArrivalType.setNextGenerator(const Value: tRndm);
begin
  aNextArrivalGenerator.Free;
  aNextArrivalGenerator := Value;
end;

end.
